#pragma once //只包含一次

#include <iostream>
#include <vector>
#include <queue>
#include <functional>
#include <thread>
#include <atomic>
#include <condition_variable>

//线程池类
class SimpleThreadPool
{
public:
    SimpleThreadPool(const size_t numThreads); //构造函数，说明需要创建的线程数量

    ~SimpleThreadPool(); //析构函数

    //加入任务的线程
    template <typename F, typename... Args>
    void Enqueue(F &&func, Args &&...args);

private:
    //线程工作的函数
    void WorkLoop();

    //线程池的全部线程
    std::vector<std::thread> _threads;

    //线程执行的任务队列
    std::queue<std::function<void()>> _tasks;

    //任务为空时让进程休眠
    std::condition_variable _condition;

    //线程池原子停止标志
    std::atomic<bool> _stop;

    //任务锁，用来保护任务队列并发的访问
    std::mutex _queue_mutex;
};

//内联构造函数
inline SimpleThreadPool::SimpleThreadPool(const size_t numThreads)
    : _stop(false) //停止标志设置为false
{
    //线程池的数量检查，不能为0
    if (numThreads == 0)
    {
        throw std::invalid_argument("SimpleThreadPool size can not be zero");
    }

    //批量创建线程，
    for (size_t i = 0; i < numThreads; i++)
    {
        _threads.emplace_back([this]{ this->WorkLoop(); });
    }
}

//内联析构函数
inline SimpleThreadPool::~SimpleThreadPool()
{
    //修改_stop
    _stop.store(true);

    //唤醒全部部的线程
    _condition.notify_all();

    //回收全部的线程
    for (auto &thread : _threads)
    {
        if (thread.joinable())
        {
            thread.join();
        }
    }
}

template <typename F, typename... Args>
void SimpleThreadPool::Enqueue(F &&func, Args &&...args)
{
    //将任务打包
    auto task = std::bind(std::forward<F>(func), std::forward<Args>(args)...);

    //加锁保证任务一次性加载成功
    {
        std::unique_lock<std::mutex> queue_lock(_queue_mutex);

        //检查线程池
        if (_stop.load())
        {
            throw std::runtime_error("SimpleThreadPool has stopped");
        }

        //加入任务使用lambda包装成void()的function
        _tasks.emplace([task](){ task(); });
    }

    //通知线程
    _condition.notify_one();
}

//线程循环任务
inline void SimpleThreadPool::WorkLoop(){
    //循环进行任务查找，知道任务存在
    while(true){
        std::function<void()> task;//创建空壳任务

        {
            //获取队列锁
            std::unique_lock<std::mutex> queue_lock(_queue_mutex);

            //判断是否有任务
            _condition.wait(queue_lock, [this]{
                return this->_stop.load() || !this->_tasks.empty();
            });

            //如果线程池已经停止了，而且任务没有了，直接停止当前线程
            if(this->_stop.load() && this->_tasks.empty()){
                return;
            }

            //有任务而且线程池没有停止
            task = std::move(_tasks.front());
            _tasks.pop();
        }
        
        //执行任务
        task();
    }
}